`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/12 22:14:09
// Design Name: 
// Module Name: ahb_master
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`define IDLE 0
`define BUSY 1
`define NOSEQ 2
`define SEQ 3


module ahb_master;
logic HCLK;
logic HRESETn;
logic [31:0] HADDR;
logic [1:0] HTRANS;
logic HWRITE;
logic [2:0] HSIZE;
logic [2:0] HBURST;
logic [3:0] HPROT;
logic [31:0] HWDATA;
logic [31:0] HRDATA;
//
logic HREADY;
logic [1:0] HRESP;
logic HSEL;
logic HREADY0;
logic [1:0] HRESP0;
logic HSEL0;
logic HREADY1;
logic [1:0] HRESP1;
logic HSEL1;
logic HREADY2;
logic [1:0] HRESP2;
logic HSEL2;
logic HREADY3;
logic [1:0] HRESP3;
logic HSEL3;
//
//parameter NOSEQ=2'b10;
//parameter SEQ=2'b11;
//parameter IDLE=2'b00;
//parameter BUSY=2'b01;
//HBURST类型
parameter SINGLE=3'b000;
parameter INCR=3'b001;
parameter WRAP4=3'b010;
parameter INCR4=3'b011;
parameter WRAP8=3'b100;
parameter INCR8=3'b101;
parameter WRAP16=3'b110;
parameter INCR16=3'b111;
//HRESP类型
parameter OKAY=2'b00;
parameter ERROR=2'b01;
parameter RETRY=2'b10;
parameter SPLIT=2'b11;
//
assign HSEL=1;                     //选中该从机
assign HSIZE=2;                    //2^2=4字节
assign HPROT=4'b0000;
//***********************************************************task*************************************************************
//pipelined multi single trans
task multi_trans(
   input [31:0] addr,
   input [31:0] data);
    //
    HBURST=SINGLE;
    HTRANS=`NOSEQ;
    HADDR=addr;
    HWRITE=1; 
    @(posedge HCLK);       //控制信号传输完成
	#1
	HADDR=addr+4;
	HWRITE=1;
	HWDATA=data;
	wait(HREADY);
	@(posedge HCLK);       //第二次控制信号传输完成,以及第一次的数据传输完成
	#1
	HADDR=addr;
	HWRITE=0;
	HWDATA=data+1;
	wait(HREADY==1'b1);
	@(posedge HCLK);                //第三次控制信号传输完成,第二次的数据传输完成
	#1
	HADDR=addr+4;
	HWRITE=0;
	wait(HREADY==1'b1);
	@(posedge HCLK);             //第四次控制信号传输完成,第三次数据读取完成
	#1
	HTRANS=`IDLE;
	//HADDR=0;
	HWDATA=0;
	wait(HREADY==1'b1);
	@(posedge HCLK);             //第四个数据读取完成
	
endtask
//single transfer
task single_trans(
   input [31:0] addr,
   input [31:0] data,
   input write);
   //
   HBURST=SINGLE;
   HTRANS=`NOSEQ;
   //HWDATA=data;
   HADDR=addr;
   HWRITE=write;
   @(posedge HCLK);           //控制信号已经被接收
   #1
   HWDATA=data;               //开始传输数据
   HTRANS=`IDLE;
   wait(HREADY==1'b1);
   @(posedge HCLK);           //数据接收完毕
   #1
   HWDATA=0;
endtask
//INCR传输
task incr_trans(
   input [31:0] len,
   input [31:0] addr,
   input [31:0] data,
   input write);
   //
   HBURST=INCR;
   HTRANS=`NOSEQ;
   HADDR=addr;
   HWRITE=write;
   @(posedge HCLK);
   for(int i=1;i<len;i++)
   begin
       #1
       HTRANS=`SEQ;
	   HADDR=addr+i*4;
	   HWDATA=data+i-1;
	   wait(HREADY);
	   @(posedge HCLK);
   end
   #1
   HTRANS=`IDLE;
   //HADDR=0;
   HWDATA=data+len-1;
   wait(HREADY);
   @(posedge HCLK);
   #1
   HWDATA=0;
endtask
//WRAP4
task wrap4_trans(
    input [31:0] data,
	input [31:0] addr,
	input write);
	//4x4=16字节,即地址遇到16的倍数时折回
	logic [31:0] base=addr&32'hffff_fff0;
	logic [31:0] offset=addr&32'h0000_000f;
	$display("base=%d,offset=%d",base,offset);
	//start transfer
	HBURST=WRAP4;
	HADDR=addr;
	HWRITE=write;
	HTRANS=`NOSEQ;
	@(posedge HCLK);                  //第一个控制信号已被接收
	for(int i=1;i<4;i++)
	begin
	   #1
	   HTRANS=`SEQ;
	   HADDR=base+(offset+4*i)%16;
	   HWDATA=data+i-1;
	   wait(HREADY);
	   @(posedge HCLK);
	end
	#1
	HTRANS=`IDLE;
	//HADDR=0;
	HWDATA=data+4-1;
	wait(HREADY);
	@(posedge HCLK);
	#1
	HWDATA=0;
	
endtask
//WRAP8
task wrap8_trans(
    input [31:0] data,
	input [31:0] addr,
	input write);
	//8x4=32字节,即地址遇到32的倍数时折回
	logic [31:0] offset=addr%32;
	logic [31:0] base=addr-offset;
	$display("base=%d,offset=%d",base,offset);
	//start transfer
	HBURST=WRAP8;
	HADDR=addr;
	HWRITE=write;
	HTRANS=`NOSEQ;
	@(posedge HCLK);                  //第一个控制信号已被接收
	for(int i=1;i<8;i++)
	begin
	   #1
	   HTRANS=`SEQ;
	   HADDR=base+(offset+4*i)%32;
	   HWDATA=data+i-1;
	   wait(HREADY);
	   @(posedge HCLK);                         //本次控制信号和上一次的数据已被接收
	end
	#1
	HTRANS=`IDLE;
	//HADDR=0;
	HWDATA=data+8-1;
	wait(HREADY);
	@(posedge HCLK);
	#1
	HWDATA=0;
endtask
//WRAP16
task wrap16_trans(
    input [31:0] data,
	input [31:0] addr,
	input write);
	//16x4=64字节,即地址遇到64的倍数时折回
	logic [31:0] offset=addr%64;
	logic [31:0] base=addr-offset;
	$display("base=%d,offset=%d",base,offset);
	//start transfer
	HBURST=WRAP16;
	HADDR=addr;
	HWRITE=write;
	HTRANS=`NOSEQ;
	@(posedge HCLK);                  //第一个控制信号已被接收
	for(int i=1;i<16;i++)
	begin
	   #1
	   HTRANS=`SEQ;
	   HADDR=base+(offset+4*i)%64;
	   HWDATA=data+i-1;
	   wait(HREADY);
	   @(posedge HCLK);
	end
	#1
	HTRANS=`IDLE;
	//HADDR=0;
	HWDATA=data+16-1;
	wait(HREADY);
	@(posedge HCLK);
	#1
	HWDATA=0;
endtask
//**************************************************************task************************************************************
//HCLK
initial
begin
   HCLK=0;
   forever
   #5 HCLK=~HCLK;
end
//HRESETn
initial
begin
   HRESETn=0;
   #50
   HRESETn=1;
end
//
initial
begin
   HTRANS=`IDLE;
   #100
   single_trans(.addr({2'b11,30'd0}+20),.data(66),.write(1));
   #100
   incr_trans(.len(8),.addr(16),.data(8),.write(1));
   #100
   wrap4_trans(.data(20),.addr({2'b01,30'd0}+20),.write(1));
   #100
   wrap8_trans(.data(48),.addr(48),.write(1));
   #100
   wrap16_trans(.data(36),.addr({2'b10,30'd0}+36),.write(1));
   #100
   multi_trans(.data(88),.addr(40));
end
//slave1
ahb_slave
#(.N(1024),
  .ID(0))
U1(
.HCLK(HCLK),
.HRESETn(HRESETn),
.HADDR({2'b00,HADDR[29:0]}),
.HTRANS(HTRANS),
.HWRITE(HWRITE),
.HSIZE(HSIZE),
.HBURST(HBURST),
.HPROT(HPROT),
.HWDATA(HWDATA),
.HRDATA(HRDATA),
.HREADY(HREADY0),
.HRESP(HRESP0),
.HSEL(HSEL0)
    );
//slave2
ahb_slave
#(.N(1024),
  .ID(1))
U2(
.HCLK(HCLK),
.HRESETn(HRESETn),
.HADDR({2'b00,HADDR[29:0]}),
.HTRANS(HTRANS),
.HWRITE(HWRITE),
.HSIZE(HSIZE),
.HBURST(HBURST),
.HPROT(HPROT),
.HWDATA(HWDATA),
.HRDATA(HRDATA),
.HREADY(HREADY1),
.HRESP(HRESP1),
.HSEL(HSEL1)
    );
//
ahb_slave
#(.N(1024),
  .ID(2))
U3(
.HCLK(HCLK),
.HRESETn(HRESETn),
.HADDR({2'b00,HADDR[29:0]}),
.HTRANS(HTRANS),
.HWRITE(HWRITE),
.HSIZE(HSIZE),
.HBURST(HBURST),
.HPROT(HPROT),
.HWDATA(HWDATA),
.HRDATA(HRDATA),
.HREADY(HREADY2),
.HRESP(HRESP2),
.HSEL(HSEL2)
    );
//
ahb_slave
#(.N(1024),
  .ID(3))
U4(
.HCLK(HCLK),
.HRESETn(HRESETn),
.HADDR({2'b00,HADDR[29:0]}),
.HTRANS(HTRANS),
.HWRITE(HWRITE),
.HSIZE(HSIZE),
.HBURST(HBURST),
.HPROT(HPROT),
.HWDATA(HWDATA),
.HRDATA(HRDATA),
.HREADY(HREADY3),
.HRESP(HRESP3),
.HSEL(HSEL3)
    );
//decoder
decoder decoder_inst(.*);
endmodule
